﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProjectPenguin.Cards;
using NSGeo.Geometry;
using ProjectPenguin.Cards.ProcessorCardHelpers;

namespace ProjectSnake
{
    // 生成的食物点不能一开始就和蛇体碰撞
    // TODO 蛇长度<xx的时候，直接生成碰撞。蛇长度>xx的时候，从set差集中抽取。
    class FoodGenerator
    {
        private readonly Dictionary<Point3d, object> feasible = new Dictionary<Point3d, object>();

        public static Point3d IntPoint(Point3d point)
        {
            return new Point3d((int)point.X, (int)point.Y, (int)point.Z);
        }

        public static Dictionary<Point3d, object> RecIntMesh(Rectangle3d rec,bool include_end=false)
        {
            var origin = IntPoint(rec.Plane.Origin);
            // Point3d有现成hash方法
            Dictionary<Point3d, object> map = new Dictionary<Point3d, object>();
            int int_X1 = (int)rec.X[0];
            int int_X2 = (int)rec.X[1];
            int int_Y1 = (int)rec.Y[0];
            int int_Y2 = (int)rec.Y[1];
            if(include_end)
            {
                for (int i = int_X1; i <= int_X2; i++)
                    for (int j = int_Y1; j <= int_Y2; j++)
                        map.Add(new Point3d(i, j, 0) + origin, null);
            }
            else
            {
                for (int i = int_X1 + 1; i < int_X2; i++)
                    for (int j = int_Y1 + 1; j < int_Y2; j++)
                        map.Add(new Point3d(i, j, 0) + origin, null);
            }
            return map;
        }

        public FoodGenerator(){}

        public FoodGenerator(Rectangle3d scene,List<Rectangle3d> forbidden=null)
        {
            if (!scene.IsValid) return;
            // 裁剪forbiden至scene，再离散。
            var scene_bb = scene.BoundingBox;
            feasible = RecIntMesh(scene, false);

            if (forbidden == null) return;
            foreach (var item in forbidden)
            {
                var inter = BoundingBox.Intersection(scene_bb, item.BoundingBox);
                var inter_rec = new Rectangle3d(item.Plane, inter.Min, inter.Max);
                var inter_map = RecIntMesh(inter_rec,true);
                foreach (var item2 in inter_map)
                    if (feasible.ContainsKey(item2.Key))
                        feasible.Remove(item2.Key);
            }
        }
        public Dictionary<Point3d, object> EliminateSnake(IEnumerable<LineCurve> lines)
        {
            // 每次单独排除snake
            Dictionary<Point3d, object> r = new Dictionary<Point3d, object>(feasible);

            if(lines!=null)
            {
                foreach (var line in lines)
                {
                    var ts = line.DivideByLength(1);
                    foreach (var item in ts) 
                        r.Remove(IntPoint(line.PointAt(item)));
                }
            }
            
            return r;
        }

        public static Point3d RandomGenerate(Dictionary<Point3d, object> r)
        {
            // 随机抽样
            Random rd = new Random();
            var id = rd.Next(1, r.Count);

            // 感觉这部分需要优化
            int ii = 0;
            foreach (var item in r.Keys)
            {
                if (ii == id) return item;
                ii++;
            }
            return new Point3d();
        }
    }


    public class FoodGeneratorCard : ProcessorCardBase
    {
        public FoodGeneratorCard() : base("食物生成器", "食物生成器", "食物生成器", "GamerDeck", "ProjectSnake") { }
        static Guid _guid = Guid.Parse("{4BBAC5DD-492F-4ADF-B5D5-5FC04990EC22}");
        public override Guid CardGuid => _guid;
        private static Point3d CurrentFood;
        private static FoodGenerator FG = null;

        public static bool Eaten = true; // 一开始要生成一次

        protected override void AddInputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "重置", "重置", "重置", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(Rectangle3d), "区域", "区域", "主区域", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(Rectangle3d), "排除区域", "排除区域", "排除区域", ProjectPenguin.Cards.Enums.DataProcessingMode.ListByList);
            helper.AddWellKnownTypeOfDataCard(typeof(LineCurve), "排除线条", "排除线条", "排除线条", ProjectPenguin.Cards.Enums.DataProcessingMode.ListByList);
            helper[2].IsOptional = true;
            helper[3].IsOptional = true;
        }

        protected override void AddOutputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(Point3d), "食物", "食物", "食物", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
        }

        public override void Build(IDataDelivery idd)
        {
            bool reset = false;

            Rectangle3d region = new Rectangle3d();
            List<Rectangle3d> forbidden_rec = new List<Rectangle3d>();
            List<LineCurve> forbidden_line = new List<LineCurve>();

            if (!idd.GetDataItem(0, ref reset)) return;
            if (!idd.GetDataItem(1, ref region)) return;
            idd.GetDataList(2, forbidden_rec);
            idd.GetDataList(3, forbidden_line);

            if (reset||Eaten)
            {
                if(reset || FG==null)
                    FG = new FoodGenerator(region,forbidden_rec);

                var r = FG.EliminateSnake(forbidden_line);
                CurrentFood = FoodGenerator.RandomGenerate(r);

                Eaten = false;
            }
            
            idd.SetDataItem(0, CurrentFood);    
        }
    }

    public class FoodEatenCard : ProcessorCardBase
    {
        public FoodEatenCard() : base("静默-吃食", "静默-吃食", "静默触发-食物被吃", "GamerDeck", "ProjectSnake") { }
        static Guid _guid = Guid.Parse("{8A59D7EA-39CB-488E-B0E7-1C508714C55C}");
        public override Guid CardGuid => _guid;

        protected override void AddInputSideDataCards(IDataCardEmbedmentHelper helper)
        {
            helper.AddWellKnownTypeOfDataCard(typeof(bool), "bool", "bool", "bool", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne);
            helper.AddWellKnownTypeOfDataCard(typeof(int), "长长", "长长", "长长多少", ProjectPenguin.Cards.Enums.DataProcessingMode.OneByOne,1);
        }

        protected override void AddOutputSideDataCards(IDataCardEmbedmentHelper helper){}

        public override void Build(IDataDelivery idd)
        {
            bool trigger = false;
            int add_length = 0;
            if (!idd.GetDataItem(0, ref trigger)) return;
            if (!idd.GetDataItem(1, ref add_length)) return;

            // 暗改
            if (trigger)
            {
                FoodGeneratorCard.Eaten = true;
                SnakeCard.Length += add_length;
            }
        }
    }
}
